//
//Copyright(c) 2020, ThorsianWay Technologies Co, Ltd
//All rights reserved.
//
//IP Name       :   ifdiv
//File Name     :   float_newton.v
//Module name   :   float_newton
//Full name     :   rcp result newton interpolation 
//
//Author        :   xiang tian
//Email         :   
//Data          :   2020/5/13
//Version       :   V1.01
//
//Abstract      :   Do newton interpolation
//                  
//Called  by    :   GPU
//
//Modification history
//-----------------------------------------------------
//1.00: intial version 
//1.01: add float monitor, add busy port
//
//-----------------------------------------------------------------------------

//-----------------------------
//DEFINE MACRO
//-----------------------------
module float_newton(
    clk,
    rst_n,
    busy,
    en,
    exp_rcp,
    man_rcp,
    man_ff,
    sign_rcp,
    iszero_rcp,
    isinf_rcp,
    isnan_rcp,
    exp_newton,
    man_newton,
    sign_newton,
    iszero_newton,
    isinf_newton,
    isnan_newton,   
    valid    
);
`include "float_monitor_func.v"

input             clk;
input             rst_n;
input             busy;
input             en;
input     [8:0]   exp_rcp;
input     [24:0]  man_rcp;
input     [24:0]  man_ff;
input             sign_rcp;
input             iszero_rcp;
input             isinf_rcp;
input             isnan_rcp;
output reg[8:0]   exp_newton;
output reg[24:0]  man_newton;
output reg        sign_newton;
output reg        iszero_newton;
output reg        isinf_newton;
output reg        isnan_newton;   
output reg        valid;


reg [26:0] newton_mult1;
reg [24:0] man_rcp_ff;
reg [8:0]  exp_rcp_ff;
reg        en_ff;
reg        sign_ff;
reg        iszero_ff;
reg        isinf_ff;
reg        isnan_ff;

wire [51:0] man_times_rcp = {1'b1,man_ff} * {1'b1,man_rcp};
wire [26:0] two = 27'h400_0000;
//wire [26:0] mult_div2_shift = {1'b0,man_times_rcp[51:26]} + man_times_rcp[25];//(man_times_rcp>/2)>>25;
wire [26:0] mult_div2_shift = (man_times_rcp>>1)>>25;
wire [26:0] newton_inter = two - mult_div2_shift;


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        sign_ff   <= 1'b0;
        iszero_ff <= 1'b0;
        isinf_ff  <= 1'b0;
        isnan_ff  <= 1'b0;  
        newton_mult1 <= 27'b0;
        man_rcp_ff <= 25'b0;
        exp_rcp_ff <= 9'b0;
    end
    else if(en && !busy)
    begin
        sign_ff  <= sign_rcp;
        iszero_ff <= iszero_rcp;
        isinf_ff  <= isinf_rcp;
        isnan_ff  <= isnan_rcp;  
        exp_rcp_ff <= exp_rcp;
        man_rcp_ff <= man_rcp;
        newton_mult1 <= newton_inter;
    end
end


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n) en_ff <= 1'b0;
    else if(!busy) en_ff <= en;
end          

//------------------------------------------------------

wire [52:0] newton_times_rcp = {1'b1,man_rcp_ff} * newton_mult1;
//wire [24:0] man_newton_inter = newton_times_rcp[50:26] + newton_times_rcp[25] ;//(newton_times_rcp>>1) >>25
wire [24:0] man_newton_inter = newton_times_rcp >>25;


//only for debug
always @(posedge clk)
begin
    if(en_ff && newton_times_rcp[52:50]!=3'b001)
    begin
        $display("Wrong floating newton calculation!\n");
        $display("AT time %t, in module %M\n",$time);
        $stop;
    end
end   


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        sign_newton   <= 1'b0;
        iszero_newton <= 1'b0;
        isinf_newton  <= 1'b0;
        isnan_newton  <= 1'b0;  
        man_newton    <= 25'b0;
        exp_newton    <= 9'b0;
    end
    else if(en_ff && !busy)
    begin
        sign_newton   <= sign_ff;
        iszero_newton <= iszero_ff;
        isinf_newton  <= isinf_ff;
        isnan_newton  <= isnan_ff;  
        man_newton    <= (man_rcp_ff == 25'b0 ) ? 25'b0 : man_newton_inter;
        exp_newton    <= exp_rcp_ff;
    end
end


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n) valid <= 1'b0;
    else if(!busy)  valid <= en_ff;
end                         

//only for monitor

wire  [31:0] float_monitor;

assign float_monitor = float_asmb(sign_newton,exp_newton[7:0],man_newton[24:2]); 

endmodule
